<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<body>
<script id="worker" type="javascript/worker">

var messageHandler = function(port, e) {
    var text_decoder = new TextDecoder;
    port.postMessage({
      content: text_decoder.decode(e.data),
      byteLength: e.data.byteLength
    });

    // Send back the array buffer.
    port.postMessage(e.data, [e.data.buffer]);

    port.postMessage({
     content: text_decoder.decode(e.data),
      byteLength: e.data.byteLength
    });
};

// For Worker.
self.addEventListener('message', e => {
    var port = e.ports[0];
    port.onmessage = messageHandler.bind(null, port);
});

// For SharedWorker.
self.addEventListener('connect', e => {
    var port = e.ports[0];
    port.onmessage = messageHandler.bind(null, port);
});

</script>

<script>

async_test(t => {
    var message = 'Hello, world!';
    var text_encoder = new TextEncoder;
    var text_decoder = new TextDecoder;

    var channel = new MessageChannel;
    channel.port1.onmessage = function(e) {
        assert_equals(e.data.byteLength, message.length);
        assert_equals(text_decoder.decode(e.data), message);
        t.done();
    };
    channel.port2.onmessage = function(e) {
        assert_equals(e.data.byteLength, message.length);
        assert_equals(text_decoder.decode(e.data), message);
        channel.port2.postMessage(e.data, [e.data.buffer]);
        assert_equals(e.data.byteLength, 0);
        assert_equals(text_decoder.decode(e.data), '');
    };

    var ab = text_encoder.encode(message);
    assert_equals(ab.byteLength, message.length);
    channel.port1.postMessage(ab, [ab.buffer]);
    assert_equals(ab.byteLength, 0);
    assert_equals(text_decoder.decode(ab.data), '');
}, 'Send a transferable ArrayBuffer within a same frame');

async_test(t => {
    var message = 'Hello, world!';
    var text_encoder = new TextEncoder;
    var text_decoder = new TextDecoder;

    var frame = document.createElement('iframe');
    frame.src = 'resources/empty.html';
    frame.onload = function() {
      frame.contentWindow.onmessage = function(evt) {
          var port = evt.data;
          port.onmessage = function(e) {
              assert_equals(e.data.byteLength, message.length);
              assert_equals(text_decoder.decode(e.data), message);
              port.postMessage(e.data, [e.data.buffer]);
              assert_equals(e.data.byteLength, 0);
              assert_equals(text_decoder.decode(e.data), '');
          };
      };

      var channel = new MessageChannel;
      channel.port1.onmessage = function(e) {
          assert_equals(e.data.byteLength, message.length);
          assert_equals(text_decoder.decode(e.data), message);
          t.done();
      };
      frame.contentWindow.postMessage(channel.port2, '*', [channel.port2]);

      var ab = text_encoder.encode(message);
      assert_equals(ab.byteLength, message.length);
      channel.port1.postMessage(ab, [ab.buffer]);
      assert_equals(ab.byteLength, 0);
      assert_equals(text_decoder.decode(ab), '');
    };
    document.body.appendChild(frame);
}, 'Send a transferable ArrayBuffer over frames');

promise_test(t => {
    var message = 'Hello, world!';
    var text_encoder = new TextEncoder;
    var text_decoder = new TextDecoder;
    var channel = new MessageChannel;

    var blob = new Blob([document.querySelector('#worker').textContent]);
    var worker = new Worker(URL.createObjectURL(blob));
    worker.postMessage(undefined, [channel.port2]);

    var ab = text_encoder.encode(message);
    assert_equals(ab.byteLength, message.length);
    channel.port1.postMessage(ab, [ab.buffer]);
    assert_equals(
      ab.byteLength, 0,
      'Byte length of a neutered buffer should be zero.');

    return new Promise(resolve => { channel.port1.onmessage = resolve; })
      .then(e => {
          // Verify the integrity of the transferred array buffer.
          assert_equals(e.data.content, message);
          assert_equals(e.data.byteLength, message.length);
          return new Promise(resolve => { channel.port1.onmessage = resolve; })
        })
      .then(e => {
          // Verify the integrity of the array buffer sent back from Worker via
          // MessagePort.
          assert_equals(text_decoder.decode(e.data), message);
          assert_equals(e.data.byteLength, message.length);
          return new Promise(resolve => { channel.port1.onmessage = resolve; })
        })
      .then(e => {
          // Verify that the array buffer on ServiceWorker is neutered.
          assert_equals(e.data.content, '');
          assert_equals(e.data.byteLength, 0);
        });
}, 'Send a transferable ArrayBuffer to Worker');

promise_test(t => {
    var message = 'Hello, world!';
    var text_encoder = new TextEncoder;
    var text_decoder = new TextDecoder;

    var blob = new Blob([document.querySelector('#worker').textContent]);
    var worker = new SharedWorker(URL.createObjectURL(blob));

    var ab = text_encoder.encode(message);
    assert_equals(ab.byteLength, message.length);
    worker.port.postMessage(ab, [ab.buffer]);
    assert_equals(
      ab.byteLength, 0,
      'Byte length of a neutered buffer should be zero.');

    return new Promise(resolve => { worker.port.onmessage = resolve; })
      .then(e => {
          // Verify the integrity of the transferred array buffer.
          assert_equals(e.data.content, message);
          assert_equals(e.data.byteLength, message.length);
          return new Promise(resolve => { worker.port.onmessage = resolve; })
        })
      .then(e => {
          // Verify the integrity of the array buffer sent back from Worker via
          // MessagePort.
          assert_equals(text_decoder.decode(e.data), message);
          assert_equals(e.data.byteLength, message.length);
          return new Promise(resolve => { worker.port.onmessage = resolve; })
        })
      .then(e => {
          // Verify that the array buffer on ServiceWorker is neutered.
          assert_equals(e.data.content, '');
          assert_equals(e.data.byteLength, 0);
        });
}, 'Send a transferable ArrayBuffer to SharedWorker');

</script>
</body>
